home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c-part1 / 1001 < prev    next >
Encoding:
Text File  |  1996-08-05  |  2.5 KB  |  74 lines

  1. Newsgroups: comp.lang.c
  2. Path: nntp.coast.net!torn!sq!msb
  3. From: msb@sq.com (Mark Brader)
  4. Subject: Re: Extracting chars from shorts.
  5. Message-ID: <1996Jan10.202721.5216@sq.com>
  6. Organization: SoftQuad Inc., Toronto, Canada
  7. References: <4d13i0$k3s@lastactionhero.rs.itd.umich.edu>
  8. Date: Wed, 10 Jan 1996 20:27:21 GMT
  9.  
  10. Tom Spindler (dogcow@monet.ccs.itd.umich.edu) writes:
  11. > I'm trying to extracts individual bytes from a double.
  12.  
  13. Apparently he means "from an unsigned short".
  14.  
  15. > The following code doesn't work:
  16. > typedef unsigned char zbyte;  /* unsigned 1 byte quantity */
  17. > typedef unsigned short zword; /* unsigned 2 byte quantity */
  18. > typedef union zw_u_t {
  19. >         zword zword;
  20. >         struct {zbyte hi,lo;} zbyte;
  21. >         } zwordun;
  22.  
  23. That's okay, given that the endianness and the type sizes are known.
  24. Personally I'd rather use an array for the zbyte member, as this
  25. clearly expresses the fact that the bytes are to be contiguous.
  26.  
  27. > #define lo(v)      ((zbyte) (((zwordun) v).zbyte.lo))
  28. > #define hi(v)      ((zbyte) (((zwordun) v).zbyte.hi))
  29. > ...
  30. > One compiler complains that it's an illegal cast, whereas gcc says that the
  31.  
  32. No other type can be converted to a union type in standard C, because
  33. the compiler would have to guess which member of the union to assign to.
  34. Instead of zfoo = lo(foon), write it with a temporary variable:
  35.  
  36.     zwordun ztemp;
  37.     ztemp.zword = foon;
  38.     zfoo = ztemp.zbyte.lo;
  39.  
  40. Having seen this, it's tempting to say
  41.  
  42.   zwordun ztemp; /* global for lo and hi macros */
  43.   #define lo(v)      (ztemp.zword = (v), ztemp.zbyte.lo) /* POOR */
  44.   #define hi(v)      (ztemp.zword = (v), ztemp.zbyte.hi) /* POOR */
  45.  
  46. but this causes undefined behavior if you use two of these expressions
  47. without a sequence point intervening, as in
  48.  
  49.     printf ("hi byte %d, lo byte %d\n", hi(x), lo(x)); /* WRONG */
  50.  
  51. And there is no way to fix this in an expression-like macro.  (The comma
  52. operators do introduce two sequence points, but you need a third one and
  53. there's no way to get it.)
  54.  
  55. Just like the case of swapping two values, using a union this way is
  56. something that is better NOT done with a macro in C.
  57.  
  58.  
  59. But why use a union?  If unsigned short is known to be 2 bytes, then
  60. all you need is
  61.  
  62.     #include <limits.h>
  63.     #define hi(v) ((v) >> CHAR_BIT)
  64.     #define lo(v) ((v) & UCHAR_MAX)
  65.  
  66. The opposite transformation is also easily accomplished with bitwise
  67. operations.
  68. -- 
  69. Mark Brader, msb@sq.com, SoftQuad Inc., Toronto
  70. #define MSB(type)       (~(((unsigned type)-1)>>1))
  71.  
  72. My text in this article is in the public domain.
  73.